package main

import (
	"antifake/casebill"
	"antifake/production"
	"antifake/util"
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	sc "github.com/hyperledger/fabric/protos/peer"
	"io"
	"os"
	"regexp"
	"strconv"
	"time"
)

type SmartContract struct {
}

type DataPre struct {
	Key   string `json:"key"`
	Value string `json:"value"`
}

var logger = shim.NewLogger("Tracker")

func (s *SmartContract) Init(APIstub shim.ChaincodeStubInterface) sc.Response {
	return shim.Success(nil)
}

func (s *SmartContract) Invoke(APIstub shim.ChaincodeStubInterface) sc.Response {

	// Retrieve the requested Smart Contract function and arguments
	function, args := APIstub.GetFunctionAndParameters()
	// Route to the appropriate handler function to interact with the ledger appropriately
	if function == "queryCar" {
		return s.queryCar(APIstub, args)
	} else if function == "enterItems" {
		return s.enterItems(APIstub, args)
	} else if function == "queryQRInfo" {
		return s.queryQRInfo(APIstub, args)
	} else if function == "setHash" {
		return s.setHash(APIstub, args)
	} else if function == "checkHash" {
		return s.checkHash(APIstub, args)
	} else if function == "dataPrepare" {
		return s.dataPrepare(APIstub, args)
	} else if function == "enterCaseBill" {
		return s.enterCaseBill(APIstub, args)
	} else if function == "dataPrepareForEach" {
		return s.dataPrepareForEach(APIstub, args)
	} else if function == "enterItemsCompressed" {
		return s.enterItemsCompressed(APIstub, args)
	} else if function == "queryQRInfoCompressed" {
		return s.queryQRInfoCompressed(APIstub, args)
	}

	return shim.Error("Invalid Smart Contract function name.")
}

func (s *SmartContract) queryCar(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	carAsBytes, _ := APIstub.GetState(args[0])
	return shim.Success(carAsBytes)
}

// 原始方法：将一批生成的码放入fabric集群中
func (s *SmartContract) enterItems(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	if len(args) != 11 {
		return shim.Error("Incorrect number of arguments. Expecting 11")
	}

	itemsInfo := production.UnitInfo{
		args[1],
		args[2],
		args[3],
		args[4],
		args[5],
		args[6],
		args[7],
		args[8],
		args[9],
	}

	var itemNos []string
	err := json.Unmarshal([]byte(args[10]), &itemNos)
	if err != nil {
		return shim.Error("系统错误。")
	}

	BatchInfo := production.ProductUnit{
		itemsInfo,
		itemNos,
	}
	return BatchInfo.SaveProductUnitInfo(APIstub, args[0])
}

// 进行数据压缩：将一批生成的码压缩后放入fabric集群中(压缩率在85% 1W条码 500KB > 75KB)
func (s *SmartContract) enterItemsCompressed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	fmt.Println("参数：")
	fmt.Println(args)


	// 添加第12个参数是压缩后的一批码的MD5值，进行数据校验
	if len(args) != 12 {
		return shim.Error("Incorrect number of arguments. Expecting 12")
	}

	//进行数据校验
	if util.MD5(args[10]) != args[11] {
		return shim.Error("校验压缩后的数据失败")
	}
	//fmt.Println("校验md5成功")
	//fmt.Println("~~~~~~~~~~~~")
	//fmt.Println(args[10])
	//fmt.Println("~~~~~~~~~~~~")
	//fmt.Println([]byte(args[10]))
	//fmt.Println("~~~~~~~~~~~~")
	itemsInfo := production.UnitInfo{
		ProductTime:   args[1],
		ItemNo:        args[2],
		EnterBatch:    args[3],
		Producer:      args[4],
		Environment:   args[5],
		MaterialBatch: args[6],
		EnterTime:     args[7],
		NumOfSonPacks: args[8],
		PackLevel:     args[9],
	}
	// 不再进行json反序列化
	//var itemNos []string
	//err := json.Unmarshal([]byte(args[10]), &itemNos)
	//if err != nil {
	//	return shim.Error("系统错误。")
	//}

	BatchInfo := production.ProductUnitCompressed{
		BatchInfo:         itemsInfo,
		UnitNosCompressed: []byte(args[10]),
	}
	return BatchInfo.SaveProductUnitInfo(APIstub, args[0])
}

func (s *SmartContract) queryQRInfo(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 8 {
		return shim.Error("Incorrect number of arguments. Expecting 8")
	}

	match, err := regexp.Match("\\(01\\)[0-9]{14}\\(10\\)([0-9]|[A-Z]){6}\\(21\\)([0-9]|[A-Z]){16}", []byte(args[0]))
	if err != nil {
		return shim.Error("系统错误。")
	}
	if !match {
		return shim.Error("二维码格式错误。")
	}

	value, err := APIstub.GetState(args[0])
	if err != nil {
		return shim.Error("系统错误。")
	} else if value == nil {
		return s.queryByQRFirstTime(APIstub, args)
	} else {
		return s.queryByQR(APIstub, args, value)
	}
}

func (s *SmartContract) queryByQRFirstTime(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	p := production.ProductUnit{}
	p.QueryProductUnitInfo(APIstub, args[0])
	qR := production.QRInfo{}
	qR.ItemInfo = p.BatchInfo
	value, err := json.Marshal(qR)
	if err != nil {
		return shim.Error("系统错误。")
	}

	err = p.Repackage(APIstub, args[1], args[2], args[0], args[3], args[4], args[5], args[6], args[7])
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(value)
}

// 根据二维码查询会涉及到第一次查询，第一次查询会涉及到解压缩
func (s *SmartContract) queryQRInfoCompressed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 8 {
		return shim.Error("Incorrect number of arguments. Expecting 8")
	}

	match, err := regexp.Match("\\(01\\)[0-9]{14}\\(10\\)([0-9]|[A-Z]){6}\\(21\\)([0-9]|[A-Z]){16}", []byte(args[0]))
	if err != nil {
		return shim.Error("正则匹配失败系统错误。")
	}
	if !match {
		return shim.Error("二维码格式错误。")
	}

	value, err := APIstub.GetState(args[0])
	//fmt.Println("查询传入的键对应的值：value："+string(value))
	if err != nil {
		return shim.Error("系统错误。")
	} else if value == nil {
		return s.queryByQRFirstTimeCompressed(APIstub, args)
	} else {
		return s.queryByQR(APIstub, args, value)
	}
}

// 第一次查询会涉及到解压缩
func (s *SmartContract) queryByQRFirstTimeCompressed(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {

	p := production.ProductUnitCompressed{}
	start := time.Now()
	p.QueryProductUnitInfo(APIstub, args[0])
	cost := time.Since(start)
	costSecondString := fmt.Sprintf("%s %f\n",args[0],cost.Seconds())
	file,_ := os.OpenFile("./cost.out",os.O_CREATE|os.O_RDWR|os.O_APPEND,0755)
	io.WriteString(file,costSecondString)
	file.Close()
	fmt.Println(costSecondString)

	qR := production.QRInfo{}
	qR.ItemInfo = p.BatchInfo
	value, err := json.Marshal(qR)
	if err != nil {
		return shim.Error("系统错误。")
	}

	err = p.Repackage(APIstub, args[1], args[2], args[0], args[3], args[4], args[5], args[6], args[7])
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(value)
}

//func operationAfterFirstQuery(APIstub shim.ChaincodeStubInterface, args []string) error {
//
//	if len(args) != 4 {
//		return fmt.Errorf("Incorrect number of arguments. Expecting 4")
//	}
//
//	p := production.ProductUnit{}
//	err := p.QueryProductUnitInfo(APIstub, args[0], args[1])
//	if err != nil {
//		return err
//	}
//	err = p.Repackage(APIstub, args[2], args[3], args[1])
//	if err != nil {
//		return err
//	}

//	return nil
//}

func (s *SmartContract) queryByQR(APIstub shim.ChaincodeStubInterface, args []string, value []byte) sc.Response {

	//if len(args) != 3 {
	//	return shim.Error("Incorrect number of arguments. Expecting 3")
	//}

	qR := production.QRInfo{}
	queriedFlag, err := qR.QueryByQR(APIstub, args[0], value, args[1], args[6], args[3], args[7])
	if err != nil {
		return shim.Error(err.Error())
	}

	if !queriedFlag {
		r := production.RepackageInfo{}
		err = r.UpdateQueryInfo(APIstub, args[1], args[2], args[0], args[3], args[4], args[5], args[6], args[7])
		if err != nil {
			return shim.Error(err.Error())
		}
		longitudeFloat, err := strconv.ParseFloat(args[4], 32)
		if err != nil {
			return shim.Error(err.Error())
		}
		latitudeFloat, err := strconv.ParseFloat(args[5], 32)
		if err != nil {
			return shim.Error(err.Error())
		}
		queryInfo := production.QueryInfo{
			//重复查询标志
			production.Address{
				args[1],
				[]float32{float32(longitudeFloat), float32(latitudeFloat)},
				args[6],
			},
			args[2],
			len(qR.QueryHistory) + 1,
			args[3],
			args[7],
		}
		qR.QueryHistory = append(qR.QueryHistory, queryInfo)
	}

	result, err := json.Marshal(qR)
	if err != nil {
		return shim.Error("系统错误。")
	}
	return shim.Success(result)
}

//func operationAfterQuery(APIstub shim.ChaincodeStubInterface, args []string) error {
//
//	if len(args) != 3 {
//		return fmt.Errorf("Incorrect number of arguments. Expecting 3")
//	}
//
//	r := production.RepackageInfo{}
//	err := r.UpdateQueryInfo(APIstub, args[1], args[2], args[0])
//	if err != nil {
//		return err
//	}
//
//	return nil
//}

func (s *SmartContract) setHash(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	err := APIstub.PutState(args[0], []byte(args[1]))
	if err != nil {
		return shim.Error("系统错误。")
	}

	return shim.Success(nil)
}

func (s *SmartContract) checkHash(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	hash, err := APIstub.GetState(args[0])
	if err != nil {
		return shim.Error(err.Error())
	}
	if hash == nil {
		return shim.Error("此键值不可用。")
	} else if string(hash) != args[1] {
		return shim.Error("出现非法数据。")
	}

	return shim.Success(nil)
}

func (s *SmartContract) dataPrepare(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}

	valueIterator, err := APIstub.GetStateByPartialCompositeKey("BatchForProduct", []string{string([]byte(args[0])[0:39])})
	if err != nil {
		return shim.Error("系统错误")
	} else if valueIterator == nil {
		return shim.Error("找不到您查询的商品。")
	}
	defer valueIterator.Close()

	var result []string

	for valueIterator.HasNext() {
		value, err := valueIterator.Next()
		if err != nil {
			return shim.Error("系统错误")
		}
		result = append(result, value.Key)
	}

	resultAsBytes, err := json.Marshal(result)
	if err != nil {
		return shim.Error("系统错误")
	}

	return shim.Success(resultAsBytes)
}

func (s *SmartContract) dataPrepareForEach(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting 1")
	}
	valueAsBytes, err := APIstub.GetState(args[0])
	if err != nil {
		return shim.Error("系统错误")
	}

	var pt production.ProductUnit
	err = json.Unmarshal(valueAsBytes, &pt)
	if err != nil {
		return shim.Error("系统错误")
	}
	unitnosAsBytes, err := json.Marshal(pt.UnitNos)
	if err != nil {
		return shim.Error("系统错误")
	}

	return shim.Success(unitnosAsBytes)
}

func (s *SmartContract) enterCase(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 2 {
		return shim.Error("Incorrect number of arguments. Expecting 2")
	}

	err := APIstub.PutState("Package"+args[0], []byte(args[1]))
	if err != nil {
		shim.Error("系统错误")
	}

	return shim.Success(nil)
}

func (s *SmartContract) enterCaseBill(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
	if len(args) != 5 {
		return shim.Error("Incorrect number of arguments. Expecting 5")
	}

	var newCaseBill casebill.CaseBill
	newCaseBill.ArgsToCaseBill(args[1:])
	newCaseBillAsBytes, err := json.Marshal(newCaseBill)
	if err != nil {
		return shim.Error("系统错误")
	}
	err = APIstub.PutState("Case"+args[0], newCaseBillAsBytes)
	if err != nil {
		return shim.Error("系统错误")
	}

	return shim.Success(nil)
}

func main() {

	//asasdadasdasdaaaa
	// Create a new Smart Contract
	err := shim.Start(new(SmartContract))
	if err != nil {
		fmt.Printf("Error creating new Smart Contract: %s", err)
	}
}
